package cn.com.oceansoft.osc.ms.utils;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author wuzy
 * @created 2017-03-07-16:03
 * @email wzy@oceansoft.com.cn
 */
public class HttpClientUtil {
    private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);
    public static final String CHARSET = "UTF-8";
    private static final CloseableHttpClient httpClient;

    public static CloseableHttpClient getClient() {
        return httpClient;
    }


    /**
     * 执行GET请求
     *
     * @param url GET请求URL字符串
     * @return 响应字符串
     * @throws HttpException 传入参数或返回状态码非200时抛出运行时错误
     */
    public static String doGet(String url) throws IOException, IllegalArgumentException, HttpException {
        if (null == url || url.trim().length() == 0) {
            throw new HttpException("URL地址错误");
        }
        String result = null;
        HttpGet httpGet = new HttpGet(url);
        CloseableHttpResponse response = null;
        try {
            if (logger.isDebugEnabled())
                logger.debug(url);
            response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
                release(response, httpGet);
                if (logger.isDebugEnabled())
                    logger.debug("HttpGet error,status code:" + statusCode);
                throw new HttpException("HttpGet error,status code:" + statusCode);
            }
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                result = EntityUtils.toString(entity, CHARSET);
            }
            EntityUtils.consume(entity);
        } finally {
            release(response, httpGet);
        }
        return result;
    }


    public static void resWriteStr(HttpServletResponse res, String str) {
        try {
            res.setCharacterEncoding(CHARSET);
            res.getWriter().print(str);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String doGetEms(String url, Map<String, String> map) throws IOException, IllegalArgumentException, HttpException {
        if (null == url || url.trim().length() == 0) {
            throw new HttpException("URL地址错误");
        }
        String result = null;
        HttpGet httpGet = new HttpGet(url);

        for (Map.Entry<String, String> entry : map.entrySet()) {

            httpGet.setHeader(entry.getKey(), entry.getValue());
        }

        CloseableHttpResponse response = null;
        try {
            if (logger.isDebugEnabled())
                logger.debug(url);
            response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) {
                release(response, httpGet);
                if (logger.isDebugEnabled())
                    logger.debug("HttpGet error,status code:" + statusCode);
                throw new HttpException("HttpGet error,status code:" + statusCode);
            }


            HttpEntity entity = response.getEntity();

            if (entity != null) {
                result = EntityUtils.toString(entity, CHARSET);
            }
            EntityUtils.consume(entity);

            map.put("requestUrl", url);
            map.put("responseInfo", result);


        } finally {
            release(response, httpGet);
        }
        return result;
    }

    /**
     * 执行带参数Get请求
     *
     * @param url    请求URL地址
     * @param params 请求参数，参数个数必须为偶数且数据类型为String,Char,int，否则产生错误<br>如："name","Tom","age",12
     * @return 响应内容
     * @throws IOException
     */
    public static String doGet(String url, Object... params) throws IOException, IllegalArgumentException, HttpException {
        return doGet(processParams(url, params));
    }

    /**
     * HTTP Post 获取内容
     *
     * @param url     请求的url地址 ?之前的地址
     * @param params  请求的参数
     * @param charset 编码格式
     * @return 页面内容
     */
    public static String doPost(String url, Map<String, String> params, String charset) {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        try {
            List<NameValuePair> pairs = null;
            if (params != null && !params.isEmpty()) {
                pairs = new ArrayList<NameValuePair>(params.size());
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    String value = entry.getValue();
                    if (value != null) {
                        pairs.add(new BasicNameValuePair(entry.getKey(), value));
                    }
                }
            }
            HttpPost httpPost = new HttpPost(url);
            if (pairs != null && pairs.size() > 0) {
                httpPost.setEntity(new UrlEncodedFormEntity(pairs, CHARSET));
            }
            CloseableHttpResponse response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                httpPost.abort();
                throw new RuntimeException("HttpClient,error status code :" + statusCode);
            }
            HttpEntity entity = response.getEntity();
            String result = null;
            if (entity != null) {
                result = EntityUtils.toString(entity, "utf-8");
            }
            EntityUtils.consume(entity);
            response.close();
            return result;
        } catch (Exception e) {
            //e.printStackTrace();
        }
        return null;
    }

    /**
     * POST请求StringEntity数据
     *
     * @param url  请求URL地址
     * @param data 请求JSON数据
     * @return String 响应JSON字符串
     * @throws IOException
     */
    public static String doPostString(String url, Object data) {
        try {
            HttpPost httpPost = new HttpPost(url);
            httpPost.setEntity(new StringEntity(JSON.toJSONString(data), ContentType.APPLICATION_JSON));
            CloseableHttpResponse response = httpClient.execute(httpPost);
            try {
                HttpEntity entity = response.getEntity();
                //System.out.println("HttpEntity=====>" + entity);
                if (null != entity) {
                    return EntityUtils.toString(entity);
                }
                return null;
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            } finally {
                release(response, httpPost);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }


    public static String doPostEms(String url, Map<String, String> params) {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        try {
            String strParams = "";
            for (Map.Entry<String, String> entry : params.entrySet()) {

                strParams += "&" + entry.getValue();

            }
            strParams = strParams.substring(1);

            HttpPost httpPost = new HttpPost(url);
            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
            httpPost.setEntity(new StringEntity(strParams));

            CloseableHttpResponse response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                httpPost.abort();
                throw new RuntimeException("HttpClient,error status code :" + statusCode);
            }
            HttpEntity entity = response.getEntity();
            String result = null;
            if (entity != null) {
                result = EntityUtils.toString(entity, CHARSET);
            }
            EntityUtils.consume(entity);
            response.close();
            return result;
        } catch (Exception e) {
            //e.printStackTrace();
        }
        return null;
    }

    public static String doPostByMap(String url, Map<String, String> params) throws Exception {
        return doPostByMap(url, params, CHARSET);
    }


    public static String doRequest(String method, String url, String data) {
        HttpURLConnection conn = null;
        try {
            // 创建一个URL对象
            URL targetUrl = new URL(url);
            // 调用URL的openConnection()方法,获取HttpURLConnection对象
            conn = (HttpURLConnection) targetUrl.openConnection();

            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("Content-Encoding", "UTF-8");

            conn.setRequestProperty("Accept", "application/json");
            conn.setRequestProperty("Accept-Charset", "UTF-8");

            conn.setReadTimeout(5000);// 设置读取超时为5秒
            conn.setConnectTimeout(10000);// 设置连接网络超时为10秒

            conn.setDoInput(true);
            if ("GET".equalsIgnoreCase(method)) {


                //}
                //if (GET == method) {
                conn.setRequestMethod("GET");// 设置请求方法为GET

            } else if ("POST".equalsIgnoreCase(method)) {
                conn.setUseCaches(false);
                conn.setDoOutput(true);// 设置此方法,允许向服务器输出内容
                byte[] dataByte = data.getBytes("UTF-8");
                conn.setRequestProperty("Content-Length", String.valueOf(dataByte.length));
                conn.setRequestProperty("Content-Language", "en-US");
                conn.setRequestMethod("POST");// 设置请求方法为POST

                DataOutputStream outputStream = new DataOutputStream(conn.getOutputStream());
                outputStream.write(dataByte);
                outputStream.flush();
                outputStream.close();
            } else if ("PUT".equalsIgnoreCase(method)) {
                conn.setUseCaches(false);
                conn.setDoOutput(true);// 设置此方法,允许向服务器输出内容
                byte[] dataByte = data.getBytes("UTF-8");
                conn.setRequestProperty("Content-Length", String.valueOf(dataByte.length));
                conn.setRequestProperty("Content-Language", "en-US");
                conn.setRequestMethod("PUT");// 设置请求方法为POST

                DataOutputStream outputStream = new DataOutputStream(conn.getOutputStream());
                outputStream.write(dataByte);
                outputStream.flush();
                outputStream.close();
            }


            int responseCode = conn.getResponseCode();// 调用此方法就不必再使用conn.connect()方法
            if (responseCode == 200) {
                InputStream is = conn.getInputStream();
                return getStringFromInputStream(is);
            } else {
                return "";
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
        return "";
    }

    /**
     * 根据流返回一个字符串信息*
     *
     * @param inputStream InputStream输入流
     * @return String
     * @throws IOException
     */
    private static String getStringFromInputStream(InputStream inputStream) throws IOException {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inputStream.read(buffer)) != -1) {
            os.write(buffer, 0, len);
        }
        inputStream.close();
        String state = os.toString();
        os.close();
        return state;
    }

    public static String doPostByMap(String url, Map<String, String> params, String charset) throws Exception {
        if (StringUtils.isBlank(url)) {
            return null;
        }


        List<NameValuePair> pairs = null;
        if (params != null && !params.isEmpty()) {
            pairs = new ArrayList<NameValuePair>(params.size());
            for (Map.Entry<String, String> entry : params.entrySet()) {
                String value = entry.getValue();
                if (value != null) {
                    pairs.add(new BasicNameValuePair(entry.getKey(), value));
                }
            }
        }
        HttpPost httpPost = new HttpPost(url);
        if (pairs != null && pairs.size() > 0) {
            httpPost.setEntity(new UrlEncodedFormEntity(pairs, charset));
        }
        CloseableHttpResponse response = httpClient.execute(httpPost);
        int statusCode = response.getStatusLine().getStatusCode();


        HttpEntity entity = response.getEntity();
        String result = null;
        if (entity != null) {
            result = EntityUtils.toString(entity, charset);
        }
        EntityUtils.consume(entity);

        if (statusCode != 200) {
            httpPost.abort();
            throw new RuntimeException("HttpClient,error status code :" + statusCode);
        }

        response.close();
        return result;


    }

    public static CloseableHttpResponse getHttpResponse(String url, Map<String, String> params) {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        try {
            url = processGetParams(url, params, CHARSET);
            HttpGet httpGet = new HttpGet(url);
            //System.out.println("URL===>" + url);
            CloseableHttpResponse response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                httpGet.abort();
                throw new RuntimeException("HttpClient,error status code :" + statusCode);
            }
            return response;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 处理GET参数
     *
     * @param url     请求的url地址 ?之前的地址
     * @param params  请求参数
     * @param charset 请求参数字符集
     * @return String
     * @throws IOException
     */
    private static String processGetParams(String url, Map<String, String> params, String charset) throws IOException {
        if (params != null && !params.isEmpty()) {
            List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
            for (Map.Entry<String, String> entry : params.entrySet()) {
                String value = entry.getValue();
                if (value != null) {
                    pairs.add(new BasicNameValuePair(entry.getKey(), value));
                }
            }
            url += "?" + EntityUtils.toString(new UrlEncodedFormEntity(pairs, charset));
        }
        return url;
    }

    /**
     * 处理请求参数
     * <br> 请求参数以可变参数形式传入，其中奇数位参数为key，偶数位参数为value.
     * <br>如：processParams("http://172.17.100.139/econsole/api/profile","name","tom","age",12,"height",188)
     *
     * @param baseUrl 资源地址
     * @param params  请求参数
     * @return String 完整请求URL 如：http://172.17.100.139/econsole/api/profile?name=tom&age=12&height=188
     * @throws IllegalArgumentException
     */
    private static String processParams(String baseUrl, Object... params) throws IllegalArgumentException {
        int len = params.length;
        StringBuilder rt = new StringBuilder(baseUrl);
        if (len > 1 && 0 == len % 2) {
            for (int i = 0; i < len; i++) {
                Object obj = params[i];
                if (obj instanceof Integer || obj instanceof String || obj instanceof Character) {
                    if (i == 0) {
                        rt.append("?");
                    } else {
                        rt.append("&");
                    }
                    rt.append(params[i]).append("=");
                    i++;
                    rt.append(params[i]);
                } else {
                    throw new IllegalArgumentException("参数类型错误，仅允许String,Character,Integer类型参数");
                }
            }
        } else if (len == 0) {
            return baseUrl;
        } else {
            throw new IllegalArgumentException("参数不正确，传入参数量必须为偶数");
        }
        return rt.toString();
    }

    /**
     * 释放链接资源
     *
     * @param response   响应流
     * @param httpMethod 执行请求方法
     */
    private static void release(Closeable response, HttpRequestBase httpMethod) {
        if (null != response) {
            try {
                response.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            httpMethod.abort();
            httpMethod.releaseConnection();
        }
    }

    static {
        PoolingHttpClientConnectionManager pcm = new PoolingHttpClientConnectionManager();
        pcm.setMaxTotal(200);
        pcm.setDefaultMaxPerRoute(pcm.getMaxTotal());
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(120000).setSocketTimeout(150000).build();
        httpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
    }
}
